package com.sxj.springsourcecode.springframework.context.config;

import com.sxj.springsourcecode.springframework.factory.BeanFactory;
import com.sxj.springsourcecode.springframework.factory.config.BeanFactoryPostProcessor;
import com.sxj.springsourcecode.springframework.factory.config.BeanPostProcessor;
import com.sxj.springsourcecode.springframework.factory.support.AbstractBeanFactory;
import com.sxj.springsourcecode.springframework.factory.support.ConfigurableListableBeanFactory;
import com.sxj.springsourcecode.springframework.io.support.DefaultResourceLoader;
import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;

import java.util.Map;

/**
 * @ProjectName: spring-source-code
 * @Package: com.sxj.springsourcecode.springframework.context.config
 * @ClassName: AbstractApplicationContext
 * @Author: sxj
 * @Description:
 * @Date: 2024/2/21 23:21
 * @Version: 1.0.0
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationConext {
    @Override
    public void refresh() {
        //1 创建bean工厂，加载bean 定义
        refreshBeanFactory();

        //2 调用bean工厂的后置处理器
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        invokeBeanFactoryPostProcessor(beanFactory);

        //3 注册bean的后置处理器
        registerBeanPostProcessor(beanFactory);

        //4 实例化 单例bean对象
        beanFactory.preInstantiateSingletons();

    }

    public abstract void refreshBeanFactory();
    public abstract ConfigurableListableBeanFactory getBeanFactory();

    /**
     * 调用bean工厂的后置处理器
     * @param beanFactory
     */
    private void invokeBeanFactoryPostProcessor(ConfigurableListableBeanFactory beanFactory){
        //1 获取后置处理器
        Map<String, BeanFactoryPostProcessor> processorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);

        //2 执行
        processorMap.forEach((k,v) ->{
            v.PostProcessBeanFactory(beanFactory);
        });

    }

    private void registerBeanPostProcessor(ConfigurableListableBeanFactory beanFactory){
        Map<String, BeanPostProcessor> processorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        processorMap.forEach((k,v) ->{
            beanFactory.addBeanPostProcessor(v);
        });

    }



    /**
     * TODO
     *
     */
    public abstract String[] getBeanDefinitionNames();

    @Override
    public Object getBean(String beanName) {
        return getBean(beanName,null);
    }

    @Override
    public Object getBean(String beanName, Object... args) {
        return getBeanFactory().getBean(beanName,args);
    }

    @Override
    public void registerShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread(this::close));
    }

    @Override
    public void close() {
        getBeanFactory().destorySingletons();
    }
}
